package edu.thu.studio.ormdesigner.model.diagram.link;

import com.thoughtworks.xstream.annotations.XStreamAlias;
import com.thoughtworks.xstream.annotations.XStreamAsAttribute;
import com.thoughtworks.xstream.annotations.XStreamOmitField;

import edu.thu.studio.ormdesigner.model.AbstractModel;
import edu.thu.studio.ormdesigner.model.diagram.node.Node;
import edu.thu.studio.ormdesigner.model.diagram.node.TableNode;
import edu.thu.studio.ormdesigner.model.orm.table.Reference;
import edu.thu.studio.ormdesigner.model.orm.table.ReferenceSet;
import edu.thu.studio.ormdesigner.util.Utils;

@XStreamAlias("link")
public class Link extends AbstractModel {
    
    private static final long serialVersionUID = -799084389600970737L;
    
    @XStreamAsAttribute
    private String from;
    
    @XStreamAsAttribute
    private String to;
    
    @XStreamAsAttribute
    @XStreamAlias("line-width")
    private Double lineWidth;
    
    @XStreamAsAttribute
    private Boolean visible = true;
    
    @XStreamOmitField()
    private Node source;
    
    @XStreamOmitField()
    private Node target;
    
    @XStreamOmitField()
    private boolean isConnected = false;
    
    @XStreamAsAttribute
    @XStreamAlias("reference-id")
    private String referenceId;
    
    @XStreamOmitField()
    private Reference reference;
    
    public Link() {
        super();
    }
    
    public Link(Node source, Node target) {
        reconnect(source, target);
    }
    
    public String getFrom() {
        return from;
    }
    
    public void setFrom(String from) {
        this.from = from;
    }
    
    public String getTo() {
        return to;
    }
    
    public void setTo(String to) {
        this.to = to;
    }
    
    public Double getLineWidth() {
        return lineWidth;
    }
    
    public void setLineWidth(Double lineWidth) {
        this.lineWidth = lineWidth;
    }
    
    public Boolean getVisible() {
        return visible;
    }
    
    public void setVisible(Boolean visible) {
        this.visible = visible;
    }
    
    public Node getSource() {
        return source;
    }
    
    public Node getTarget() {
        return target;
    }
    
    public void setSource(Node source) {
        this.source = source;
        if (null != source) {
            this.from = source.getId();
        } else {
            this.from = null;
        }
    }
    
    public void setTarget(Node target) {
        this.target = target;
        if (null != target) {
            this.to = target.getId();
        } else {
            this.to = null;
        }
    }
    
    public String getReferenceId() {
        return referenceId;
    }
    
    public void setReferenceId(String referenceId) {
        this.referenceId = referenceId;
    }
    
    public void disconnect() {
        if (isConnected) {
            source.removeOutgoing(this);
            target.removeIncoming(this);
            LinkSet links = this.target.getDiagram().getLinks();
            if (links.contains(this)) {
                links.remove(this);
            }
            if (source instanceof TableNode) {
                ReferenceSet references = source.getRefTable().getReferences();
                if (null != referenceId) {
                    reference = references.get(referenceId);
                    if (null != reference) {
                        references.remove(reference);
                    }
                }
                
            }
            isConnected = false;
        }
    }
    
    public void reconnect() {
        if (!isConnected) {
            if (this.source != null) {
                source.addOutgoing(this);
            }
            if (this.target != null) {
                target.addIncoming(this);
            }
            LinkSet links = this.target.getDiagram().getLinks();
            if (!links.contains(this)) {
                links.addObject(this);
            }
            if (source instanceof TableNode) {
                ReferenceSet references = source.getRefTable().getReferences();
                if (null != reference) {
                    if (!references.contains(reference)) {
                        references.addObject(reference);
                    }
                }
                
            }
            isConnected = true;
        }
    }
    
    public void reconnect(Node newSource, Node newTarget) {
        if (newSource == null || newTarget == null || newSource == newTarget) {
            throw new IllegalArgumentException();
        }
        disconnect();
        setSource(newSource);
        setTarget(newTarget);
        reconnect();
    }
    
    public void checkAndInit() {
        if (null == id) {
            id = Utils.getUUID();
        }
    }
    
}
